/*
OpenMVL Matrix Vector Library
Copyright (c) 2009 FluidInteractive (R)
 
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising
from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
Written by: Nicola Candussi <nicola@fluidinteractive.com>
*/

//meta_vector.hpp

#ifndef MVL_META_VECTOR_HPP
#define MVL_META_VECTOR_HPP

#include "meta.hpp"

namespace mvl { 

namespace meta {

struct vector_tag { };

template<typename T0 = none, typename T1 = none, typename T2 = none, typename T3 = none, typename T4 = none,
         typename T5 = none, typename T6 = none, typename T7 = none, typename T8 = none, typename T9 = none>   
struct vector
{
    //
    typedef vector_tag  tag;
    typedef vector      type;
    //
    typedef T0  t0;
    typedef T1  t1;
    typedef T2  t2;
    typedef T3  t3;
    typedef T4  t4;
    typedef T5  t5;
    typedef T6  t6;
    typedef T7  t7;
    typedef T8  t8;
    typedef T9  t9;
}; //namespace mvl

//size implementation
template<typename T0, typename T1, typename T2, typename T3, typename T4, 
         typename T5, typename T6, typename T7, typename T8, typename T9>
struct vector_size: int_<10> { };

template<typename T0, typename T1, typename T2, typename T3, typename T4, 
         typename T5, typename T6, typename T7, typename T8>
struct vector_size<T0, T1, T2, T3, T4, T5, T6, T7, T8, none>: int_<9> { };

template<typename T0, typename T1, typename T2, typename T3, typename T4, 
         typename T5, typename T6, typename T7>
struct vector_size<T0, T1, T2, T3, T4, T5, T6, T7, none, none>: int_<8> { };

template<typename T0, typename T1, typename T2, typename T3, typename T4, 
         typename T5, typename T6>
struct vector_size<T0, T1, T2, T3, T4, T5, T6, none, none, none>: int_<7> { };

template<typename T0, typename T1, typename T2, typename T3, typename T4, 
         typename T5>
struct vector_size<T0, T1, T2, T3, T4, T5, none, none, none, none>: int_<6> { };

template<typename T0, typename T1, typename T2, typename T3, typename T4>
struct vector_size<T0, T1, T2, T3, T4, none, none, none, none, none>: int_<5> { };

template<typename T0, typename T1, typename T2, typename T3>
struct vector_size<T0, T1, T2, T3, none, none, none, none, none, none>: int_<4> { };

template<typename T0, typename T1, typename T2>
struct vector_size<T0, T1, T2, none, none, none, none, none, none, none>: int_<3> { };

template<typename T0, typename T1>
struct vector_size<T0, T1, none, none, none, none, none, none, none, none>: int_<2> { };

template<typename T0>
struct vector_size<T0, none, none, none, none, none, none, none, none, none>: int_<1> { };

template<>
struct vector_size<none, none, none, none, none, none, none, none, none, none>: int_<0> { };

template<>
struct size_impl<vector_tag>
{
    template<typename V>
    struct apply: vector_size<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                              typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> {      
    };
};

//at implementation
template<typename Vector, int N> struct vector_at;
template<typename Vector> struct vector_at<Vector, 0> { typedef typename Vector::t0 type; };
template<typename Vector> struct vector_at<Vector, 1> { typedef typename Vector::t1 type; };
template<typename Vector> struct vector_at<Vector, 2> { typedef typename Vector::t2 type; };
template<typename Vector> struct vector_at<Vector, 3> { typedef typename Vector::t3 type; };
template<typename Vector> struct vector_at<Vector, 4> { typedef typename Vector::t4 type; };
template<typename Vector> struct vector_at<Vector, 5> { typedef typename Vector::t5 type; };
template<typename Vector> struct vector_at<Vector, 6> { typedef typename Vector::t6 type; };
template<typename Vector> struct vector_at<Vector, 7> { typedef typename Vector::t7 type; };
template<typename Vector> struct vector_at<Vector, 8> { typedef typename Vector::t8 type; };
template<typename Vector> struct vector_at<Vector, 9> { typedef typename Vector::t9 type; };

template<>
struct at_impl<vector_tag>
{
    template<typename Vector, typename N>
    struct apply: vector_at<Vector, N::value> { };
};

//clear
template<>
struct clear_impl<vector_tag>
{
    template<typename Vector>
    struct apply: vector<> { };
};

//push_front
template<>
struct push_front_impl<vector_tag>
{
    template<typename  V, typename T>
    struct apply: vector<T, typename V::t0, typename V::t1, typename V::t2, typename V::t3, 
                        typename V::t4, typename V::t5, typename V::t6, typename V::t7, typename V::t8> { };
};

//push_back
template<typename V, typename T, int N>
struct vector_push_back;
template<typename V, typename T>
struct vector_push_back<V, T, 0> : vector<T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 1> : vector<typename V::t0, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 2> : vector<typename V::t0, typename V::t1, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 3> : vector<typename V::t0, typename V::t1, typename V::t2, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 4> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 5> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4, 
                                    T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 6> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 7> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 8> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, T> {};
template<typename V, typename T>
struct vector_push_back<V, T, 9> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, T> {};

template<>
struct push_back_impl<vector_tag>
{
    template<typename Vector, typename T>
    struct apply: vector_push_back<
        Vector, T, size<Vector>::value
    > { };
};

//REPLACE_ELEMENT
template<typename V, int Pos, typename NewT> struct vector_replace_element;
template<typename V, typename NewT> 
struct vector_replace_element<V, 0, NewT> : vector<NewT, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 1, NewT> : vector<typename V::t0, NewT, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 2, NewT> : vector<typename V::t0, typename V::t1, NewT, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 3, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, NewT, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 4, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, NewT,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 5, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        NewT, typename V::t6, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 6, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, NewT, typename V::t7, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 7, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, NewT, typename V::t8, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 8, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, NewT, typename V::t9> { };
template<typename V, typename NewT> 
struct vector_replace_element<V, 9, NewT> : vector<typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                                        typename V::t5, typename V::t6, typename V::t7, typename V::t8, NewT> { };
//replace_element_impl
template<>
struct replace_element_impl<vector_tag>
{
    template<typename V, typename Pos, typename NewT>
    struct apply : vector_replace_element<V, Pos::value, NewT> { };
};

//ITERATORS
template<typename Vector, typename Pos>
struct vector_iterator 
{
    typedef random_access_iterator_tag  category;
    typedef vector_iterator             type;
};

//begin impl
template<>
struct begin_impl<vector_tag>
{
    template<typename V>
    struct apply {
        typedef vector_iterator<V, int_<0> > type;
    };
};

//end impl
template<>
struct end_impl<vector_tag>
{
    template<typename V>
    struct apply {
        typedef vector_iterator<
            V, 
            typename vector_size<
                typename V::t0, typename V::t1, typename V::t2, typename V::t3, typename V::t4,
                typename V::t5, typename V::t6, typename V::t7, typename V::t8, typename V::t9
            >::type
        > 
        type;
    };
};

//next
template<typename Vector, typename Pos>
struct next<vector_iterator<Vector, Pos> >
{
    typedef vector_iterator<Vector, typename next<Pos>::type> type;
};

//prior
template<typename Vector, typename Pos>
struct prior<vector_iterator<Vector, Pos> >
{
    typedef vector_iterator<Vector, typename prior<Pos>::type> type;
};

//deref
template<typename Vector, typename Pos>
struct deref<vector_iterator<Vector, Pos> > : at<Vector, Pos> {};

//advance
template<typename Vector, typename Pos, typename N>
struct advance<vector_iterator<Vector, Pos>, N> 
{
    typedef vector_iterator<
        Vector,
        typename plus<Pos, N>::type
    > type;
};

template<typename Vector, typename Pos1, typename Pos2>
struct distance<
    vector_iterator<Vector, Pos1>,
    vector_iterator<Vector, Pos2>
> : minus<Pos2, Pos1> {}; 

template<typename Vector, typename Pos1, typename Pos2>
struct equal_to<
    vector_iterator<Vector, Pos1>,
    vector_iterator<Vector, Pos2>
> : equal_to<Pos1, Pos2> { }; 

template<typename Vector, typename Pos1, typename Pos2>
struct not_equal_to<
    vector_iterator<Vector, Pos1>,
    vector_iterator<Vector, Pos2>
> : not_equal_to<Pos1, Pos2> { }; 

//integer vector
template<int i0 = 0, int i1 = 0, int i2 = 0, int i3 = 0, int i4 = 0,
         int i5 = 0, int i6 = 0, int i7 = 0, int i8 = 0, int i9 = 0 >
struct ivector : vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4>,
                        int_<i5>, int_<i6>, int_<i7>, int_<i8>, int_<i9> > {};

template<> 
struct ivector<> : vector<> {};
template<int i0> 
struct ivector<i0> : vector<int_<i0> > {};
template<int i0, int i1>
struct ivector<i0, i1 > : vector<int_<i0>, int_<i1> > {};
template<int i0, int i1, int i2>
struct ivector<i0, i1, i2 > : vector<int_<i0>, int_<i1>, int_<i2> > {};
template<int i0, int i1, int i2, int i3>
struct ivector<i0, i1, i2, i3 > : vector<int_<i0>, int_<i1>, int_<i2>, int_<i3> > {};
template<int i0, int i1, int i2, int i3, int i4>
struct ivector<i0, i1, i2, i3, i4 > : vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4> > {};
template<int i0, int i1, int i2, int i3, int i4, int i5>
struct ivector<i0, i1, i2, i3, i4, i5> : 
vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4>, int_<i5> > {};
template<int i0, int i1, int i2, int i3, int i4, int i5, int i6>
struct ivector<i0, i1, i2, i3, i4, i5, i6> : 
vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4>, int_<i5>, int_<i6> > {};
template<int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7>
struct ivector<i0, i1, i2, i3, i4, i5, i6, i7> : 
vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4>, int_<i5>, int_<i6>, int_<i7> > {};
template<int i0, int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8>
struct ivector<i0, i1, i2, i3, i4, i5, i6, i7, i8> : 
vector<int_<i0>, int_<i1>, int_<i2>, int_<i3>, int_<i4>, int_<i5>, int_<i6>, int_<i7>, int_<i8> > {};

//vector of type T
template<typename T, typename Size> struct tvector;
template<typename T> struct tvector<T, int_<0> > : vector<> {};
template<typename T> struct tvector<T, int_<1> > : vector<T> {};
template<typename T> struct tvector<T, int_<2> > : vector<T, T> {};
template<typename T> struct tvector<T, int_<3> > : vector<T, T, T> {};
template<typename T> struct tvector<T, int_<4> > : vector<T, T, T, T> {};
template<typename T> struct tvector<T, int_<5> > : vector<T, T, T, T, T> {};
template<typename T> struct tvector<T, int_<6> > : vector<T, T, T, T, T, T> {};
template<typename T> struct tvector<T, int_<7> > : vector<T, T, T, T, T, T, T> {};
template<typename T> struct tvector<T, int_<8> > : vector<T, T, T, T, T, T, T, T> {};
template<typename T> struct tvector<T, int_<9> > : vector<T, T, T, T, T, T, T, T, T> {};
template<typename T> struct tvector<T, int_<10> > : vector<T, T, T, T, T, T, T, T, T, T> {};

} //namespace meta

} //namespace mvl

#endif

